<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta name="keywords" content="Hexo Theme Keep"><meta name="description" content="Hexo Theme Keep"><meta name="author" content="CaiXiaoDong"><title>JavaScript-继承与原型链(Herencia y la cadena de prototipos) | 给淑芬的笔记</title><link rel="stylesheet" href="/css/style.css"><link rel="shortcut icon" href="/images/avatar.gif"><link rel="stylesheet" href="/css/font-awesome.min.css"><script id="hexo-configurations">let KEEP=window.KEEP||{};KEEP.hexo_config={hostname:"example.com",root:"/",language:"zh-CN"},KEEP.theme_config={toc:{enable:!0,number:!1,expand_all:!1,init_open:!0},style:{primary_color:"#0066CC",avatar:"/images/avatar.gif",favicon:"/images/avatar.gif",article_img_align:"left",left_side_width:"260px",content_max_width:"920px",hover:{shadow:!1,scale:!1},first_screen:{enable:!0,background_img:"/images/bg.svg",description:"最是人间留不住,朱颜辞镜花辞树."},scroll:{progress_bar:{enable:!1},percent:{enable:!0}}},local_search:{enable:!0,preload:!0},code_copy:{enable:!0,style:"default"},pjax:{enable:!0},lazyload:{enable:!0},version:"3.4.5"},KEEP.language_ago={second:"%s 秒前",minute:"%s 分钟前",hour:"%s 小时前",day:"%s 天前",week:"%s 周前",month:"%s 个月前",year:"%s 年前"}</script><meta name="generator" content="Hexo 6.1.0"></head><body><div class="progress-bar-container"><span class="pjax-progress-bar"></span> <span class="pjax-progress-icon"><i class="fas fa-circle-notch fa-spin"></i></span></div><main class="page-container"><div class="page-main-content"><div class="page-main-content-top"><header class="header-wrapper"><div class="header-content"><div class="left"><a class="logo-title" href="/">给淑芬的笔记</a></div><div class="right"><div class="pc"><ul class="menu-list"><li class="menu-item"><a href="/">首页</a></li><li class="menu-item"><a href="/archives">归档</a></li><li class="menu-item"><a href="/categories">分类</a></li><li class="menu-item"><a href="/tags">标签</a></li><li class="menu-item"><a href="/about">关于</a></li><li class="menu-item search search-popup-trigger"><i class="fas fa-search"></i></li></ul></div><div class="mobile"><div class="icon-item search search-popup-trigger"><i class="fas fa-search"></i></div><div class="icon-item menu-bar"><div class="menu-bar-middle"></div></div></div></div></div><div class="header-drawer"><ul class="drawer-menu-list"><li class="drawer-menu-item flex-center"><a href="/">首页</a></li><li class="drawer-menu-item flex-center"><a href="/archives">归档</a></li><li class="drawer-menu-item flex-center"><a href="/categories">分类</a></li><li class="drawer-menu-item flex-center"><a href="/tags">标签</a></li><li class="drawer-menu-item flex-center"><a href="/about">关于</a></li></ul></div><div class="window-mask"></div></header></div><div class="page-main-content-middle"><div class="main-content"><div class="fade-in-down-animation"><div class="article-content-container"><div class="article-title"><span class="title-hover-animation">JavaScript-继承与原型链(Herencia y la cadena de prototipos)</span></div><div class="article-header"><div class="avatar"><img src="/images/avatar.gif"></div><div class="info"><div class="author"><span class="name">CaiXiaoDong</span> <span class="author-label">Lv2</span></div><div class="meta-info"><div class="article-meta-info"><span class="article-date article-meta-item"><i class="fas fa-edit"></i>&nbsp; <span class="pc">2022-04-14 13:44:45</span> <span class="mobile">2022-04-14 13:44</span> </span><span class="article-categories article-meta-item"><i class="fas fa-folder"></i>&nbsp;<ul><li><a href="/categories/JavaScript/">JavaScript</a>&nbsp;</li></ul></span><span class="article-tags article-meta-item"><i class="fas fa-tags"></i>&nbsp;<ul><li><a href="/tags/%E5%89%8D%E7%AB%AF/">前端</a>&nbsp;</li><li>| <a href="/tags/JavaScript/">JavaScript</a>&nbsp;</li></ul></span><span class="article-pv article-meta-item"><i class="fas fa-eye"></i>&nbsp;<span id="busuanzi_value_page_pv"></span></span></div></div></div></div><div class="article-content markdown-body"><h2 id="本文出处"><a href="#本文出处" class="headerlink" title="本文出处"></a>本文出处</h2><p><a class="link" target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">继承与原型链 JavaScript | MDN<i class="fas fa-external-link-alt"></i></a></p><h2 id="继承于原型链"><a href="#继承于原型链" class="headerlink" title="继承于原型链"></a>继承于原型链</h2><p>对于使用过基于类的语言 (如 Java 或 C++) 的开发者们来说，JavaScript 实在是有些令人困惑 —— JavaScript 是动态的，本身不提供一个 <code>class</code> 的实现。即便是在 ES2015&#x2F;ES6 中引入了 <code>class</code> 关键字，但那也只是语法糖，JavaScript 仍然是基于原型的。</p><p>当谈到继承时，JavaScript 只有一种结构：对象。每个实例对象（object）都有一个私有属性（称之为 <code>__proto__</code> ）指向它的构造函数的原型对象（<code>prototype</code>）。该原型对象也有一个自己的原型对象（<code>__proto__</code>），层层向上直到一个对象的原型对象为 <code>null</code>。根据定义，<code>null</code> 没有原型，并作为这个原型链中的最后一个环节。</p><p>几乎所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。</p><p>尽管这种原型继承通常被认为是 JavaScript 的弱点之一，但是原型继承模型本身实际上比经典模型更强大。例如，在原型模型的基础上构建经典模型相当简单。</p><h2 id="基于原型链的继承"><a href="#基于原型链的继承" class="headerlink" title="基于原型链的继承"></a>基于原型链的继承</h2><h3 id="继承属性-Inheriting-properties"><a href="#继承属性-Inheriting-properties" class="headerlink" title="继承属性(Inheriting properties)"></a>继承属性(Inheriting properties)</h3><p>JavaScript 对象是动态的属性“包”（指其自己的属性）。JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时，它不仅仅在该对象上搜寻，还会搜寻该对象的原型，以及该对象的原型的原型，依次层层向上搜索，直到找到一个名字匹配的属性或到达原型链的末尾。</p><blockquote><p>备注：遵循ECMAScript标准，<code>someObject.[[Prototype]]</code> 符号是用于指向 <code>someObject</code> 的原型。从 ECMAScript 6 开始，<code>[[Prototype]]</code> 可以通过 <code>Object.getPrototypeOf()</code> 和 <code>Object.setPrototypeOf()</code> 访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性 <code>__proto__</code>。<br>但它不应该与构造函数 <code>func</code> 的 <code>prototype</code> 属性相混淆。被构造函数创建的实例对象的 <code>[[Prototype]]</code> 指向 <code>func</code> 的 <code>prototype</code> 属性。<code>Object.prototype</code> 属性表示 <code>Object</code> 的原型对象。</p></blockquote><p>这里演示当尝试访问属性时会发生什么：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 让我们从一个函数里创建一个对象o，它自身拥有属性a和b的：</span></span><br><span class="line"><span class="keyword">let</span> f = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">   <span class="variable language_">this</span>.<span class="property">a</span> = <span class="number">1</span>;</span><br><span class="line">   <span class="variable language_">this</span>.<span class="property">b</span> = <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/* 这么写也一样</span></span><br><span class="line"><span class="comment">function f() &#123;</span></span><br><span class="line"><span class="comment">  this.a = 1;</span></span><br><span class="line"><span class="comment">  this.b = 2;</span></span><br><span class="line"><span class="comment">&#125;</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">let</span> o = <span class="keyword">new</span> <span class="title function_">f</span>(); <span class="comment">// &#123;a: 1, b: 2&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 在f函数的原型上定义属性</span></span><br><span class="line">f.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">b</span> = <span class="number">3</span>;</span><br><span class="line">f.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">c</span> = <span class="number">4</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 不要在 f 函数的原型上直接定义 f.prototype = &#123;b:3,c:4&#125;;这样会直接打破原型链</span></span><br><span class="line"><span class="comment">// o.[[Prototype]] 有属性 b 和 c</span></span><br><span class="line"><span class="comment">//  (其实就是 o.__proto__ 或者 o.constructor.prototype)</span></span><br><span class="line"><span class="comment">// o.[[Prototype]].[[Prototype]] 是 Object.prototype.</span></span><br><span class="line"><span class="comment">// 最后o.[[Prototype]].[[Prototype]].[[Prototype]]是null</span></span><br><span class="line"><span class="comment">// 这就是原型链的末尾，即 null，</span></span><br><span class="line"><span class="comment">// 根据定义，null 就是没有 [[Prototype]]。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 综上，整个原型链如下:</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// &#123;a:1, b:2&#125; ---&gt; &#123;b:3, c:4&#125; ---&gt; Object.prototype---&gt; null</span></span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(o.<span class="property">a</span>); <span class="comment">// 1</span></span><br><span class="line"><span class="comment">// a是o的自身属性吗？是的，该属性的值为 1</span></span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(o.<span class="property">b</span>); <span class="comment">// 2</span></span><br><span class="line"><span class="comment">// b是o的自身属性吗？是的，该属性的值为 2</span></span><br><span class="line"><span class="comment">// 原型上也有一个&#x27;b&#x27;属性，但是它不会被访问到。</span></span><br><span class="line"><span class="comment">// 这种情况被称为&quot;属性遮蔽 (property shadowing)&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(o.<span class="property">c</span>); <span class="comment">// 4</span></span><br><span class="line"><span class="comment">// c是o的自身属性吗？不是，那看看它的原型上有没有</span></span><br><span class="line"><span class="comment">// c是o.[[Prototype]]的属性吗？是的，该属性的值为 4</span></span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(o.<span class="property">d</span>); <span class="comment">// undefined</span></span><br><span class="line"><span class="comment">// d 是 o 的自身属性吗？不是，那看看它的原型上有没有</span></span><br><span class="line"><span class="comment">// d 是 o.[[Prototype]] 的属性吗？不是，那看看它的原型上有没有</span></span><br><span class="line"><span class="comment">// o.[[Prototype]].[[Prototype]] 为 null，停止搜索</span></span><br><span class="line"><span class="comment">// 找不到 d 属性，返回 undefined</span></span><br></pre></td></tr></table></figure><p>给对象设置属性会创建自有属性。获取和设置行为规则的唯一例外是当继承的属性带有 <a class="link" target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Working_with_Objects#%E5%AE%9A%E4%B9%89_getters_%E4%B8%8E_setters">getter 或 setter<i class="fas fa-external-link-alt"></i></a> 时。</p><h3 id="继承方法-Inheriting-“methods”"><a href="#继承方法-Inheriting-“methods”" class="headerlink" title="继承方法(Inheriting “methods”)"></a>继承方法(Inheriting “methods”)</h3><p>JavaScript 并没有其他基于类的语言所定义的“方法(methods)”。在 JavaScript 里，任何函数都可以添加到对象上作为对象的属性。函数的继承与其他的属性继承没有差别，包括上面的“属性遮蔽”（这种情况相当于其他语言的方法重写）。</p><p>当继承的函数被调用时，<a class="link" target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this">this<i class="fas fa-external-link-alt"></i></a> 指向的是当前继承的对象，而不是继承的函数所在的原型对象。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> o = &#123;</span><br><span class="line">  <span class="attr">a</span>: <span class="number">2</span>,</span><br><span class="line">  <span class="attr">m</span>: <span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">a</span> + <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(o.<span class="title function_">m</span>()); <span class="comment">// 3</span></span><br><span class="line"><span class="comment">// 当调用 o.m 时，&#x27;this&#x27; 指向了 o.</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> p = <span class="title class_">Object</span>.<span class="title function_">create</span>(o);</span><br><span class="line"><span class="comment">// p是一个继承自 o 的对象</span></span><br><span class="line"></span><br><span class="line">p.<span class="property">a</span> = <span class="number">4</span>; <span class="comment">// 创建 p 的自身属性 &#x27;a&#x27;</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(p.<span class="title function_">m</span>()); <span class="comment">// 5</span></span><br><span class="line"><span class="comment">// 调用 p.m 时，&#x27;this&#x27; 指向了 p</span></span><br><span class="line"><span class="comment">// 又因为 p 继承了 o 的 m 函数</span></span><br><span class="line"><span class="comment">// 所以，此时的 &#x27;this.a&#x27; 即 p.a，就是 p 的自身属性 &#x27;a&#x27; </span></span><br></pre></td></tr></table></figure><h3 id="在-JavaScript-中使用原型-prototype"><a href="#在-JavaScript-中使用原型-prototype" class="headerlink" title="在 JavaScript 中使用原型(prototype)"></a>在 JavaScript 中使用原型(prototype)</h3><p>接下来，来仔细分析一下这些应用场景下， JavaScript 在背后做了哪些事情。</p><p>正如之前提到的，在 JavaScript 中，函数（<code>function</code>）是允许拥有属性的。所有的函数会有一个特别的属性 —— <code>prototype</code> 。请注意，以下的代码是独立的（出于严谨，假定页面没有其他的JavaScript代码）。为了最佳的学习体验，我们强烈建议阁下打开浏览器的控制台（在Chrome和火狐浏览器中，按Ctrl+Shift+I即可），进入“console”选项卡，然后把如下的JavaScript代码复制粘贴到窗口中，最后通过按下回车键运行代码。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">doSomething</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>( doSomething.<span class="property"><span class="keyword">prototype</span></span> );</span><br><span class="line"><span class="comment">// 和声明函数的方式无关，</span></span><br><span class="line"><span class="comment">// JavaScript 中的函数永远有一个默认原型属性。</span></span><br><span class="line"><span class="keyword">var</span> doSomething = <span class="keyword">function</span>(<span class="params"></span>)&#123;&#125;;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>( doSomething.<span class="property"><span class="keyword">prototype</span></span> );</span><br></pre></td></tr></table></figure><p>在控制台显示的JavaScript代码块中，我们可以看到doSomething函数的一个默认属性prototype。而这段代码运行之后，控制台应该显示类似如下的结果：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    <span class="attr">constructor</span>: ƒ <span class="title function_">doSomething</span>(),</span><br><span class="line">    <span class="attr">__proto__</span>: &#123;</span><br><span class="line">        <span class="attr">constructor</span>: ƒ <span class="title class_">Object</span>(),</span><br><span class="line">        <span class="attr">hasOwnProperty</span>: ƒ <span class="title function_">hasOwnProperty</span>(),</span><br><span class="line">        <span class="attr">isPrototypeOf</span>: ƒ <span class="title function_">isPrototypeOf</span>(),</span><br><span class="line">        <span class="attr">propertyIsEnumerable</span>: ƒ <span class="title function_">propertyIsEnumerable</span>(),</span><br><span class="line">        <span class="attr">toLocaleString</span>: ƒ <span class="title function_">toLocaleString</span>(),</span><br><span class="line">        <span class="attr">toString</span>: ƒ <span class="title function_">toString</span>(),</span><br><span class="line">        <span class="attr">valueOf</span>: ƒ <span class="title function_">valueOf</span>()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>我们可以给doSomething函数的原型对象添加新属性，如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">doSomething</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line">doSomething.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">foo</span> = <span class="string">&quot;bar&quot;</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>( doSomething.<span class="property"><span class="keyword">prototype</span></span> );</span><br></pre></td></tr></table></figure><p>可以看到运行后的结果如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    <span class="attr">foo</span>: <span class="string">&quot;bar&quot;</span>,</span><br><span class="line">    <span class="attr">constructor</span>: ƒ <span class="title function_">doSomething</span>(),</span><br><span class="line">    <span class="attr">__proto__</span>: &#123;</span><br><span class="line">        <span class="attr">constructor</span>: ƒ <span class="title class_">Object</span>(),</span><br><span class="line">        <span class="attr">hasOwnProperty</span>: ƒ <span class="title function_">hasOwnProperty</span>(),</span><br><span class="line">        <span class="attr">isPrototypeOf</span>: ƒ <span class="title function_">isPrototypeOf</span>(),</span><br><span class="line">        <span class="attr">propertyIsEnumerable</span>: ƒ <span class="title function_">propertyIsEnumerable</span>(),</span><br><span class="line">        <span class="attr">toLocaleString</span>: ƒ <span class="title function_">toLocaleString</span>(),</span><br><span class="line">        <span class="attr">toString</span>: ƒ <span class="title function_">toString</span>(),</span><br><span class="line">        <span class="attr">valueOf</span>: ƒ <span class="title function_">valueOf</span>()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>现在我们可以通过new操作符来创建基于这个原型对象的doSomething实例。使用new操作符，只需在调用doSomething函数语句之前添加new。这样，便可以获得这个函数的一个实例对象。一些属性就可以添加到该原型对象中。</p><p>请尝试运行以下代码：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">doSomething</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line">doSomething.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">foo</span> = <span class="string">&quot;bar&quot;</span>; <span class="comment">// add a property onto the prototype</span></span><br><span class="line"><span class="keyword">var</span> doSomeInstancing = <span class="keyword">new</span> <span class="title function_">doSomething</span>();</span><br><span class="line">doSomeInstancing.<span class="property">prop</span> = <span class="string">&quot;some value&quot;</span>; <span class="comment">// add a property onto the object</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>( doSomeInstancing );</span><br></pre></td></tr></table></figure><p>运行的结果类似于以下的语句。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    <span class="attr">prop</span>: <span class="string">&quot;some value&quot;</span>,</span><br><span class="line">    <span class="attr">__proto__</span>: &#123;</span><br><span class="line">        <span class="attr">foo</span>: <span class="string">&quot;bar&quot;</span>,</span><br><span class="line">        <span class="attr">constructor</span>: ƒ <span class="title function_">doSomething</span>(),</span><br><span class="line">        <span class="attr">__proto__</span>: &#123;</span><br><span class="line">            <span class="attr">constructor</span>: ƒ <span class="title class_">Object</span>(),</span><br><span class="line">            <span class="attr">hasOwnProperty</span>: ƒ <span class="title function_">hasOwnProperty</span>(),</span><br><span class="line">            <span class="attr">isPrototypeOf</span>: ƒ <span class="title function_">isPrototypeOf</span>(),</span><br><span class="line">            <span class="attr">propertyIsEnumerable</span>: ƒ <span class="title function_">propertyIsEnumerable</span>(),</span><br><span class="line">            <span class="attr">toLocaleString</span>: ƒ <span class="title function_">toLocaleString</span>(),</span><br><span class="line">            <span class="attr">toString</span>: ƒ <span class="title function_">toString</span>(),</span><br><span class="line">            <span class="attr">valueOf</span>: ƒ <span class="title function_">valueOf</span>()</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如上所示, <code>doSomeInstancing</code> 中的<code>__proto__</code>是 <code>doSomething.prototype</code>. 但这是做什么的呢？当你访问<code>doSomeInstancing</code> 中的一个属性，浏览器首先会查看<code>doSomeInstancing</code> 中是否存在这个属性。</p><p>如果 <code>doSomeInstancing</code> 不包含属性信息, 那么浏览器会在 <code>doSomeInstancing</code> 的 <code>__proto__</code> 中进行查找(同 <code>doSomething.prototype</code>). 如属性在 <code>doSomeInstancing</code> 的 <code>__proto__</code> 中查找到，则使用 <code>doSomeInstancing</code> 中 <code>__proto__</code> 的属性。</p><p>否则，如果 <code>doSomeInstancing</code> 中 <code>__proto__</code> 不具有该属性，则检查 <code>doSomeInstancing</code> 的 <code>__proto__</code> 的 <code>__proto__</code> 是否具有该属性。默认情况下，任何函数的原型属性 <code>__proto__</code> 都是 <code>window.Object.prototype</code>. 因此, 通过 <code>doSomeInstancing</code> 的 <code>__proto__</code> 的 <code>__proto__</code> ( 同 <code>doSomething.prototype</code> 的 <code>__proto__</code> (同 <code>Object.prototype</code>)) 来查找要搜索的属性。</p><p>如果属性不存在 <code>doSomeInstancing</code> 的 <code>__proto__</code> 的 <code>__proto__</code> 中， 那么就会在 <code>doSomeInstancing</code> 的 <code>__proto__</code> 的 <code>__proto__</code> 的 <code>__proto__</code> 中查找。然而, 这里存在个问题： <code>doSomeInstancing</code> 的 <code>__proto__</code> 的 <code>__proto__</code> 的 <code>__proto__</code> 其实不存在。因此，只有这样，在 <code>__proto__</code> 的整个原型链被查看之后，这里没有更多的 <code>__proto__</code> ， 浏览器断言该属性不存在，并给出属性值为 undefined 的结论。</p><p>让我们在控制台窗口中输入更多的代码，如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">doSomething</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line">doSomething.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">foo</span> = <span class="string">&quot;bar&quot;</span>;</span><br><span class="line"><span class="keyword">var</span> doSomeInstancing = <span class="keyword">new</span> <span class="title function_">doSomething</span>();</span><br><span class="line">doSomeInstancing.<span class="property">prop</span> = <span class="string">&quot;some value&quot;</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;doSomeInstancing.prop:      &quot;</span> + doSomeInstancing.<span class="property">prop</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;doSomeInstancing.foo:       &quot;</span> + doSomeInstancing.<span class="property">foo</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;doSomething.prop:           &quot;</span> + doSomething.<span class="property">prop</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;doSomething.foo:            &quot;</span> + doSomething.<span class="property">foo</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;doSomething.prototype.prop: &quot;</span> + doSomething.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">prop</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;doSomething.prototype.foo:  &quot;</span> + doSomething.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">foo</span>);</span><br></pre></td></tr></table></figure><p>结果如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">doSomeInstancing.<span class="property">prop</span>:      some value</span><br><span class="line">doSomeInstancing.<span class="property">foo</span>:       bar</span><br><span class="line">doSomething.<span class="property">prop</span>:           <span class="literal">undefined</span></span><br><span class="line">doSomething.<span class="property">foo</span>:            <span class="literal">undefined</span></span><br><span class="line">doSomething.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">prop</span>: <span class="literal">undefined</span></span><br><span class="line">doSomething.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">foo</span>:  bar</span><br></pre></td></tr></table></figure><h2 id="使用不同的方法来创建对象和生成原型链-create-objects-and-the-resulting-prototype-chain"><a href="#使用不同的方法来创建对象和生成原型链-create-objects-and-the-resulting-prototype-chain" class="headerlink" title="使用不同的方法来创建对象和生成原型链(create objects and the resulting prototype chain)"></a>使用不同的方法来创建对象和生成原型链(create objects and the resulting prototype chain)</h2><h3 id="使用语法结构创建的对象"><a href="#使用语法结构创建的对象" class="headerlink" title="使用语法结构创建的对象"></a>使用语法结构创建的对象</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> o = &#123;<span class="attr">a</span>: <span class="number">1</span>&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// o 这个对象继承了 Object.prototype 上面的所有属性</span></span><br><span class="line"><span class="comment">// o 自身没有名为 hasOwnProperty 的属性</span></span><br><span class="line"><span class="comment">// hasOwnProperty 是 Object.prototype 的属性</span></span><br><span class="line"><span class="comment">// 因此 o 继承了 Object.prototype 的 hasOwnProperty</span></span><br><span class="line"><span class="comment">// Object.prototype 的原型为 null</span></span><br><span class="line"><span class="comment">// 原型链如下:</span></span><br><span class="line"><span class="comment">// o ---&gt; Object.prototype ---&gt; null</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> a = [<span class="string">&quot;yo&quot;</span>, <span class="string">&quot;whadup&quot;</span>, <span class="string">&quot;?&quot;</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">// 数组都继承于 Array.prototype</span></span><br><span class="line"><span class="comment">// (Array.prototype 中包含 indexOf, forEach 等方法)</span></span><br><span class="line"><span class="comment">// 原型链如下:</span></span><br><span class="line"><span class="comment">// a ---&gt; Array.prototype ---&gt; Object.prototype ---&gt; null</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">f</span>(<span class="params"></span>)&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 函数都继承于 Function.prototype</span></span><br><span class="line"><span class="comment">// (Function.prototype 中包含 call, bind等方法)</span></span><br><span class="line"><span class="comment">// 原型链如下:</span></span><br><span class="line"><span class="comment">// f ---&gt; Function.prototype ---&gt; Object.prototype ---&gt; null</span></span><br></pre></td></tr></table></figure><h3 id="使用构造器创建的对象"><a href="#使用构造器创建的对象" class="headerlink" title="使用构造器创建的对象"></a>使用构造器创建的对象</h3><p>在 JavaScript 中，构造器其实就是一个普通的函数。当使用 new 操作符 来作用这个函数时，它就可以被称为构造方法（构造函数）。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Graph</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">vertices</span> = [];</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">edges</span> = [];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="title class_">Graph</span>.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">  <span class="attr">addVertex</span>: <span class="keyword">function</span>(<span class="params">v</span>)&#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">vertices</span>.<span class="title function_">push</span>(v);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> g = <span class="keyword">new</span> <span class="title class_">Graph</span>();</span><br><span class="line"><span class="comment">// g 是生成的对象，他的自身属性有 &#x27;vertices&#x27; 和 &#x27;edges&#x27;。</span></span><br><span class="line"><span class="comment">// 在 g 被实例化时，g.[[Prototype]] 指向了 Graph.prototype。</span></span><br></pre></td></tr></table></figure><h3 id="使用-Object-create-创建的对象"><a href="#使用-Object-create-创建的对象" class="headerlink" title="使用 Object.create 创建的对象"></a>使用 Object.create 创建的对象</h3><p>ECMAScript 5 中引入了一个新方法：<a class="link" target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create">Object.create()<i class="fas fa-external-link-alt"></i></a>。可以调用这个方法来创建一个新对象。使用现有的对象来提供新创建的对象的__proto__：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> person = &#123;</span><br><span class="line">  <span class="attr">isHuman</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="attr">printIntroduction</span>: <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`My name is <span class="subst">$&#123;<span class="variable language_">this</span>.name&#125;</span>. Am I human? <span class="subst">$&#123;<span class="variable language_">this</span>.isHuman&#125;</span>`</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> me = <span class="title class_">Object</span>.<span class="title function_">create</span>(person);</span><br><span class="line"></span><br><span class="line">me.<span class="property">name</span> = <span class="string">&#x27;Matthew&#x27;</span>; <span class="comment">// &quot;name&quot; is a property set on &quot;me&quot;, but not on &quot;person&quot;</span></span><br><span class="line">me.<span class="property">isHuman</span> = <span class="literal">true</span>; <span class="comment">// inherited properties can be overwritten</span></span><br><span class="line"></span><br><span class="line">me.<span class="title function_">printIntroduction</span>();</span><br><span class="line"><span class="comment">// expected output: &quot;My name is Matthew. Am I human? true&quot;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="使用-class-关键字创建的对象"><a href="#使用-class-关键字创建的对象" class="headerlink" title="使用 class 关键字创建的对象"></a>使用 class 关键字创建的对象</h3><p>ECMAScript6 引入了一套新的关键字用来实现 <a class="link" target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes">class<i class="fas fa-external-link-alt"></i></a>。使用基于类语言的开发人员会对这些结构感到熟悉，但它们是不同的。JavaScript 仍然基于原型。这些新的关键字包括 <a class="link" target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes">class<i class="fas fa-external-link-alt"></i></a>, <a class="link" target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/constructor">constructor<i class="fas fa-external-link-alt"></i></a>，<a class="link" target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/static">static<i class="fas fa-external-link-alt"></i></a>，<a class="link" target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/extends">extends<i class="fas fa-external-link-alt"></i></a> 和 <a class="link" target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/super">super<i class="fas fa-external-link-alt"></i></a>。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&quot;use strict&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Polygon</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">height, width</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">height</span> = height;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">width</span> = width;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Square</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Polygon</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">sideLength</span>) &#123;</span><br><span class="line">    <span class="variable language_">super</span>(sideLength, sideLength);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">get</span> <span class="title function_">area</span>() &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">height</span> * <span class="variable language_">this</span>.<span class="property">width</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">set</span> <span class="title function_">sideLength</span>(<span class="params">newLength</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">height</span> = newLength;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">width</span> = newLength;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> square = <span class="keyword">new</span> <span class="title class_">Square</span>(<span class="number">2</span>);</span><br></pre></td></tr></table></figure><h3 id="性能"><a href="#性能" class="headerlink" title="性能"></a>性能</h3><p>在原型链上查找属性比较耗时，对性能有副作用，这在性能要求苛刻的情况下很重要。另外，试图访问不存在的属性时会遍历整个原型链。</p><p>遍历对象的属性时，原型链上的每个可枚举属性都会被枚举出来。要检查对象是否具有自己定义的属性，而不是其原型链上的某个属性，则可使用所有对象从 <code>Object.prototype</code> 继承的 <a class="link" target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty">hasOwnProperty (en-US)<i class="fas fa-external-link-alt"></i></a> 方法也可使用<a class="link" target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/keys">Object.keys()<i class="fas fa-external-link-alt"></i></a>。下面给出一个具体的例子来说明它：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(g.<span class="title function_">hasOwnProperty</span>(<span class="string">&#x27;vertices&#x27;</span>));</span><br><span class="line"><span class="comment">// true</span></span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(g.<span class="title function_">hasOwnProperty</span>(<span class="string">&#x27;nope&#x27;</span>));</span><br><span class="line"><span class="comment">// false</span></span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(g.<span class="title function_">hasOwnProperty</span>(<span class="string">&#x27;addVertex&#x27;</span>));</span><br><span class="line"><span class="comment">// false</span></span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(g.<span class="property">__proto__</span>.<span class="title function_">hasOwnProperty</span>(<span class="string">&#x27;addVertex&#x27;</span>));</span><br><span class="line"><span class="comment">// true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// simple array</span></span><br><span class="line"><span class="keyword">var</span> arr = [<span class="string">&#x27;a&#x27;</span>, <span class="string">&#x27;b&#x27;</span>, <span class="string">&#x27;c&#x27;</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Object</span>.<span class="title function_">keys</span>(arr)); <span class="comment">// console: [&#x27;0&#x27;, &#x27;1&#x27;, &#x27;2&#x27;]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// array like object</span></span><br><span class="line"><span class="keyword">var</span> obj = &#123; <span class="number">0</span>: <span class="string">&#x27;a&#x27;</span>, <span class="number">1</span>: <span class="string">&#x27;b&#x27;</span>, <span class="number">2</span>: <span class="string">&#x27;c&#x27;</span> &#125;;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Object</span>.<span class="title function_">keys</span>(obj)); <span class="comment">// console: [&#x27;0&#x27;, &#x27;1&#x27;, &#x27;2&#x27;]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// array like object with random key ordering</span></span><br><span class="line"><span class="keyword">var</span> anObj = &#123; <span class="number">100</span>: <span class="string">&#x27;a&#x27;</span>, <span class="number">2</span>: <span class="string">&#x27;b&#x27;</span>, <span class="number">7</span>: <span class="string">&#x27;c&#x27;</span> &#125;;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Object</span>.<span class="title function_">keys</span>(anObj)); <span class="comment">// console: [&#x27;2&#x27;, &#x27;7&#x27;, &#x27;100&#x27;]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// getFoo is a property which isn&#x27;t enumerable</span></span><br><span class="line"><span class="keyword">var</span> myObj = <span class="title class_">Object</span>.<span class="title function_">create</span>(&#123;&#125;, &#123;</span><br><span class="line">  <span class="attr">getFoo</span>: &#123;</span><br><span class="line">    <span class="attr">value</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123; <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">foo</span>; &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line">myObj.<span class="property">foo</span> = <span class="number">1</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Object</span>.<span class="title function_">keys</span>(myObj)); <span class="comment">// console: [&#x27;foo&#x27;]</span></span><br></pre></td></tr></table></figure><p>注意：检查属性是否为 <code>undefined</code> 是不能够检查其是否存在的。该属性可能已存在，但其值恰好被设置成了 <code>undefined</code>。</p><h3 id="错误实践：扩展原生对象的原型"><a href="#错误实践：扩展原生对象的原型" class="headerlink" title="错误实践：扩展原生对象的原型"></a>错误实践：扩展原生对象的原型</h3><p>经常使用的一个错误实践是扩展 <code>Object.prototype</code> 或其他内置原型。</p><p>这种技术被称为猴子补丁并且会破坏封装。尽管一些流行的框架（如 Prototype.js）在使用该技术，但仍然没有足够好的理由使用附加的非标准方法来混入内置原型。</p><p>扩展内置原型的唯一理由是支持 JavaScript 引擎的新特性，如 <code>Array.forEach</code>。</p><h3 id="总结：4-个用于拓展原型链的方法"><a href="#总结：4-个用于拓展原型链的方法" class="headerlink" title="总结：4 个用于拓展原型链的方法"></a>总结：4 个用于拓展原型链的方法</h3><p>下面列举四种用于拓展原型链的方法，以及他们的优势和缺陷。下列四个例子都创建了完全相同的 inst 对象（所以在控制台上的输出也是一致的），为了举例，唯一的区别是他们的创建方法不同。</p><h4 id="New-initialization"><a href="#New-initialization" class="headerlink" title="New-initialization"></a>New-initialization</h4><p><strong>例子</strong>:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line">foo.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">  <span class="attr">foo_prop</span>: <span class="string">&quot;foo val&quot;</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">bar</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line"><span class="keyword">var</span> proto = <span class="keyword">new</span> foo;</span><br><span class="line">proto.<span class="property">bar_prop</span> = <span class="string">&quot;bar val&quot;</span>;</span><br><span class="line">bar.<span class="property"><span class="keyword">prototype</span></span> = proto;</span><br><span class="line"><span class="keyword">var</span> inst = <span class="keyword">new</span> bar;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">foo_prop</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">bar_prop</span>);</span><br></pre></td></tr></table></figure><blockquote><p><strong>优势</strong>: 支持目前以及所有可想象到的浏览器(IE5.5都可以使用)。 这种方法非常快，非常符合标准，并且充分利用JIT优化。</p></blockquote><blockquote><p><strong>缺陷</strong>: 为使用此方法，必须对相关函数初始化。 在初始化过程中，构造函数可以存储每个对象必须生成的唯一信息。但是，这种唯一信息只生成一次，可能会带来潜在的问题。此外，构造函数的初始化，可能会将不需要的方法放在对象上。然而，如果你只在自己的代码中使用，你也清楚（或有通过注释等写明）各段代码在做什么，这些在大体上都不是问题（事实上，通常是有益处的）。</p></blockquote><h4 id="Object-create"><a href="#Object-create" class="headerlink" title="Object.create"></a>Object.create</h4><p><strong>例子</strong>:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line">foo.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">  <span class="attr">foo_prop</span>: <span class="string">&quot;foo val&quot;</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">bar</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line"><span class="keyword">var</span> proto = <span class="title class_">Object</span>.<span class="title function_">create</span>(</span><br><span class="line">  foo.<span class="property"><span class="keyword">prototype</span></span></span><br><span class="line">);</span><br><span class="line">proto.<span class="property">bar_prop</span> = <span class="string">&quot;bar val&quot;</span>;</span><br><span class="line">bar.<span class="property"><span class="keyword">prototype</span></span> = proto;</span><br><span class="line"><span class="keyword">var</span> inst = <span class="keyword">new</span> bar;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">foo_prop</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">bar_prop</span>);</span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line">foo.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">  <span class="attr">foo_prop</span>: <span class="string">&quot;foo val&quot;</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">bar</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line"><span class="keyword">var</span> proto = <span class="title class_">Object</span>.<span class="title function_">create</span>(</span><br><span class="line">  foo.<span class="property"><span class="keyword">prototype</span></span>,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">bar_prop</span>: &#123;</span><br><span class="line">      <span class="attr">value</span>: <span class="string">&quot;bar val&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">);</span><br><span class="line">bar.<span class="property"><span class="keyword">prototype</span></span> = proto;</span><br><span class="line"><span class="keyword">var</span> inst = <span class="keyword">new</span> bar;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">foo_prop</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">bar_prop</span>)</span><br></pre></td></tr></table></figure><blockquote><p><strong>优点</strong>:支持当前所有非微软版本或者 IE9 以上版本的浏览器。允许一次性地直接设置 <code>__proto__</code> 属性，以便浏览器能更好地优化对象。同时允许通过 <code>Object.create(null)</code> 来创建一个没有原型的对象。</p></blockquote><blockquote><p><strong>缺点</strong>:不支持 IE8 以下的版本。然而，随着微软不再对系统中运行的旧版本浏览器提供支持，这将不是在大多数应用中的主要问题。 另外，这个慢对象初始化在使用第二个参数的时候有可能成为一个性能黑洞，因为每个对象的描述符属性都有自己的描述对象。当以对象的格式处理成百上千的对象描述的时候，可能会造成严重的性能问题。</p></blockquote><h4 id="Object-setPrototypeOf"><a href="#Object-setPrototypeOf" class="headerlink" title="Object.setPrototypeOf"></a>Object.setPrototypeOf</h4><p><strong>例子</strong>:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line">foo.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">  <span class="attr">foo_prop</span>: <span class="string">&quot;foo val&quot;</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">bar</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line"><span class="keyword">var</span> proto = &#123;</span><br><span class="line">  <span class="attr">bar_prop</span>: <span class="string">&quot;bar val&quot;</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">setPrototypeOf</span>(</span><br><span class="line">  proto, foo.<span class="property"><span class="keyword">prototype</span></span></span><br><span class="line">);</span><br><span class="line">bar.<span class="property"><span class="keyword">prototype</span></span> = proto;</span><br><span class="line"><span class="keyword">var</span> inst = <span class="keyword">new</span> bar;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">foo_prop</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">bar_prop</span>);</span><br><span class="line"></span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line">foo.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">  <span class="attr">foo_prop</span>: <span class="string">&quot;foo val&quot;</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">bar</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line"><span class="keyword">var</span> proto;</span><br><span class="line">proto=<span class="title class_">Object</span>.<span class="title function_">setPrototypeOf</span>(</span><br><span class="line">  &#123; <span class="attr">bar_prop</span>: <span class="string">&quot;bar val&quot;</span> &#125;,</span><br><span class="line">  foo.<span class="property"><span class="keyword">prototype</span></span></span><br><span class="line">);</span><br><span class="line">bar.<span class="property"><span class="keyword">prototype</span></span> = proto;</span><br><span class="line"><span class="keyword">var</span> inst = <span class="keyword">new</span> bar;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">foo_prop</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">bar_prop</span>)</span><br></pre></td></tr></table></figure><blockquote><p><strong>优点</strong>:支持所有现代浏览器和微软IE9+浏览器。允许动态操作对象的原型，甚至能强制给通过 <code>Object.create(null)</code> 创建出来的没有原型的对象添加一个原型。</p></blockquote><blockquote><p><strong>缺点</strong>:这个方式表现并不好，应该被弃用。如果你在生产环境中使用这个方法，那么快速运行 Javascript 就是不可能的，因为许多浏览器优化了原型，尝试在调用实例之前猜测方法在内存中的位置，但是动态设置原型干扰了所有的优化，甚至可能使浏览器为了运行成功，使用完全未经优化的代码进行重编译。 不支持 IE8 及以下的浏览器版本。</p></blockquote><h4 id="proto"><a href="#proto" class="headerlink" title="__proto__"></a><code>__proto__</code></h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line">foo.<span class="property"><span class="keyword">prototype</span></span> = &#123;</span><br><span class="line">  <span class="attr">foo_prop</span>: <span class="string">&quot;foo val&quot;</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">bar</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line"><span class="keyword">var</span> proto = &#123;</span><br><span class="line">  <span class="attr">bar_prop</span>: <span class="string">&quot;bar val&quot;</span>,</span><br><span class="line">  <span class="attr">__proto__</span>: foo.<span class="property"><span class="keyword">prototype</span></span></span><br><span class="line">&#125;;</span><br><span class="line">bar.<span class="property"><span class="keyword">prototype</span></span> = proto;</span><br><span class="line"><span class="keyword">var</span> inst = <span class="keyword">new</span> bar;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">foo_prop</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">bar_prop</span>);</span><br><span class="line"></span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> inst = &#123;</span><br><span class="line">  <span class="attr">__proto__</span>: &#123;</span><br><span class="line">    <span class="attr">bar_prop</span>: <span class="string">&quot;bar val&quot;</span>,</span><br><span class="line">    <span class="attr">__proto__</span>: &#123;</span><br><span class="line">      <span class="attr">foo_prop</span>: <span class="string">&quot;foo val&quot;</span>,</span><br><span class="line">      <span class="attr">__proto__</span>: <span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">foo_prop</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(inst.<span class="property">bar_prop</span>)</span><br></pre></td></tr></table></figure><blockquote><p><strong>优点</strong>:支持所有现代非微软版本以及 IE11 以上版本的浏览器。将 <strong>proto</strong> 设置为非对象的值会静默失败，并不会抛出错误。</p></blockquote><blockquote><p><strong>缺点</strong>:应该完全将其抛弃因为这个行为完全不具备性能可言。 如果你在生产环境中使用这个方法，那么快速运行 Javascript 就是不可能的，因为许多浏览器优化了原型，尝试在调用实例之前猜测方法在内存中的位置，但是动态设置原型干扰了所有的优化，甚至可能使浏览器为了运行成功，使用完全未经优化的代码进行重编译。不支持 IE10 及以下的浏览器版本。</p></blockquote><h2 id="prototype-和-Object-getPrototypeOf"><a href="#prototype-和-Object-getPrototypeOf" class="headerlink" title="prototype 和 Object.getPrototypeOf"></a>prototype 和 Object.getPrototypeOf</h2><p>对于从 Java 或 C++ 转过来的开发人员来说，JavaScript 会有点让人困惑，因为它完全是动态的，都是运行时，而且不存在类（class）。所有的都是实例（对象）。即使我们模拟出的 “类”，也只是一个函数对象。</p><p>你可能已经注意到我们的 <code>function A</code> 有一个叫做 <code>prototype</code> 的特殊属性。该特殊属性可与 JavaScript 的 <code>new</code> 操作符一起使用。对原型对象的引用被复制到新实例的内部 <code>[[Prototype]]</code> 属性。例如，当执行 <code>var a1 = new A();</code> 时，JavaScript（在内存中创建对象之后，和在运行函数 <code>A()</code> 把 <code>this</code> 指向对象之前）设置 <code>a1.[[Prototype]] = A.prototype;</code>。然后当您访问实例的属性时，JavaScript 首先会检查它们是否直接存在于该对象上，如果不存在，则会 <code>[[Prototype]]</code> 中查找。这意味着你在 <code>prototype</code> 中定义的所有内容都可以由所有实例有效地共享，你甚至可以稍后更改部分 <code>prototype</code>，并在所有现有实例中显示更改（如果有必要的话）。</p><p>像上面的例子中，如果你执行 <code>var a1 = new A(); var a2 = new A();</code> 那么 <code>a1.doSomething</code> 事实上会指向 <code>Object.getPrototypeOf(a1).doSomething</code>，它就是你在 <code>A.prototype.doSomething</code> 中定义的内容。也就是说：<code>Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething</code>（补充：实际上，执行 <code>a1.doSomething()</code> 相当于执行 <code>Object.getPrototypeOf(a1).doSomething.call(a1)==A.prototype.doSomething.call(a1)</code>）</p><p>简而言之， <code>prototype</code> 是用于类的，而 <code>Object.getPrototypeOf()</code> 是用于实例的（instances），两者功能一致。</p><p>[[Prototype]] 看起来就像递归引用， 如 <code>a1.doSomething</code>、<code>Object.getPrototypeOf(a1).doSomething</code>、<code>Object.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething</code> 等等等， 直到它被找到或 <code>Object.getPrototypeOf</code> 返回 <code>null</code>。</p><p>因此，当你执行：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> o = <span class="keyword">new</span> <span class="title class_">Foo</span>();</span><br></pre></td></tr></table></figure><p>JavaScript 实际上执行的是：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> o = <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line">o.<span class="property">__proto__</span> = <span class="title class_">Foo</span>.<span class="property"><span class="keyword">prototype</span></span>;</span><br><span class="line"><span class="title class_">Foo</span>.<span class="title function_">call</span>(o);</span><br></pre></td></tr></table></figure><p>（或者类似上面这样的），然后，当你执行：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">o.<span class="property">someProp</span>;</span><br></pre></td></tr></table></figure><p>它检查 o 是否具有 <code>someProp</code> 属性。如果没有，它会查找 <code>Object.getPrototypeOf(o).someProp</code>，如果仍旧没有，它会继续查找 <code>Object.getPrototypeOf(Object.getPrototypeOf(o)).someProp</code>。</p><h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><p>在使用原型继承编写复杂代码之前，理解原型继承模型是至关重要的。此外，请注意代码中原型链的长度，并在必要时将其分解，以避免可能的性能问题。此外，原生原型不应该被扩展，除非它是为了与新的 JavaScript 特性兼容。</p></div><div class="post-copyright-info"><div class="article-copyright-info-container"><ul><li>本文标题：JavaScript-继承与原型链(Herencia y la cadena de prototipos)</li><li>本文作者：CaiXiaoDong</li><li>创建时间：2022-04-14 13:44:45</li><li>本文链接：http://example.com/2022/04/14/javascript-prototype/</li><li>版权声明：本博客所有文章除特别声明外，均采用 <a class="license" target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">BY-NC-SA</a> 许可协议。转载请注明出处！</li></ul></div></div><ul class="post-tags-box"><li class="tag-item"><a href="/tags/%E5%89%8D%E7%AB%AF/">#前端</a>&nbsp;</li><li class="tag-item"><a href="/tags/JavaScript/">#JavaScript</a>&nbsp;</li></ul><div class="article-nav"><div class="article-prev"><a class="prev" rel="prev" href="/2022/04/21/easy-mock-build/"><span class="left arrow-icon flex-center"><i class="fas fa-chevron-left"></i> </span><span class="title flex-center"><span class="post-nav-title-item">easy-mock-build-windows</span> <span class="post-nav-item">上一篇</span></span></a></div><div class="article-next"><a class="next" rel="next" href="/2022/04/12/Vue-Monitor-Object/"><span class="title flex-center"><span class="post-nav-title-item">Vue-Object变化监测</span> <span class="post-nav-item">下一篇</span> </span><span class="right arrow-icon flex-center"><i class="fas fa-chevron-right"></i></span></a></div></div></div></div></div></div><div class="page-main-content-bottom"><footer class="footer"><div class="info-container"><div class="copyright-info info-item">&copy; <span>2020</span> - 2022&nbsp;<i class="fas fa-heart icon-animate"></i>&nbsp;<a href="/">CaiXiaoDong</a></div><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><div class="website-count info-item"><span id="busuanzi_container_site_uv">访问人数&nbsp;<span id="busuanzi_value_site_uv"></span>&ensp; </span><span id="busuanzi_container_site_pv">总访问量&nbsp;<span id="busuanzi_value_site_pv"></span></span></div><div class="theme-info info-item">由 <a target="_blank" href="https://hexo.io">Hexo</a> 驱动&nbsp;|&nbsp;主题&nbsp;<a class="theme-version" target="_blank" href="https://github.com/XPoet/hexo-theme-keep">Keep v3.4.5</a></div></div></footer></div></div><div class="post-tools"><div class="post-tools-container"><ul class="tools-list"><li class="tools-item page-aside-toggle"><i class="fas fa-outdent"></i></li></ul></div></div><div class="right-bottom-side-tools"><div class="side-tools-container"><ul class="side-tools-list"><li class="tools-item tool-font-adjust-plus flex-center"><i class="fas fa-search-plus"></i></li><li class="tools-item tool-font-adjust-minus flex-center"><i class="fas fa-search-minus"></i></li><li class="tools-item tool-expand-width flex-center"><i class="fas fa-arrows-alt-h"></i></li><li class="tools-item tool-dark-light-toggle flex-center"><i class="fas fa-moon"></i></li><li class="tools-item tool-scroll-to-bottom flex-center"><i class="fas fa-arrow-down"></i></li></ul><ul class="exposed-tools-list"><li class="tools-item tool-toggle-show flex-center"><i class="fas fa-cog fa-spin"></i></li><li class="tools-item tool-scroll-to-top flex-center"><i class="arrow-up fas fa-arrow-up"></i> <span class="percent"></span></li></ul></div></div><aside class="page-aside"><div class="post-toc-wrap"><div class="post-toc"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%9C%AC%E6%96%87%E5%87%BA%E5%A4%84"><span class="nav-text">本文出处</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF%E4%BA%8E%E5%8E%9F%E5%9E%8B%E9%93%BE"><span class="nav-text">继承于原型链</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%9F%BA%E4%BA%8E%E5%8E%9F%E5%9E%8B%E9%93%BE%E7%9A%84%E7%BB%A7%E6%89%BF"><span class="nav-text">基于原型链的继承</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF%E5%B1%9E%E6%80%A7-Inheriting-properties"><span class="nav-text">继承属性(Inheriting properties)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%BB%A7%E6%89%BF%E6%96%B9%E6%B3%95-Inheriting-%E2%80%9Cmethods%E2%80%9D"><span class="nav-text">继承方法(Inheriting “methods”)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%9C%A8-JavaScript-%E4%B8%AD%E4%BD%BF%E7%94%A8%E5%8E%9F%E5%9E%8B-prototype"><span class="nav-text">在 JavaScript 中使用原型(prototype)</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E6%96%B9%E6%B3%95%E6%9D%A5%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1%E5%92%8C%E7%94%9F%E6%88%90%E5%8E%9F%E5%9E%8B%E9%93%BE-create-objects-and-the-resulting-prototype-chain"><span class="nav-text">使用不同的方法来创建对象和生成原型链(create objects and the resulting prototype chain)</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E8%AF%AD%E6%B3%95%E7%BB%93%E6%9E%84%E5%88%9B%E5%BB%BA%E7%9A%84%E5%AF%B9%E8%B1%A1"><span class="nav-text">使用语法结构创建的对象</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E6%9E%84%E9%80%A0%E5%99%A8%E5%88%9B%E5%BB%BA%E7%9A%84%E5%AF%B9%E8%B1%A1"><span class="nav-text">使用构造器创建的对象</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8-Object-create-%E5%88%9B%E5%BB%BA%E7%9A%84%E5%AF%B9%E8%B1%A1"><span class="nav-text">使用 Object.create 创建的对象</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8-class-%E5%85%B3%E9%94%AE%E5%AD%97%E5%88%9B%E5%BB%BA%E7%9A%84%E5%AF%B9%E8%B1%A1"><span class="nav-text">使用 class 关键字创建的对象</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%80%A7%E8%83%BD"><span class="nav-text">性能</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%94%99%E8%AF%AF%E5%AE%9E%E8%B7%B5%EF%BC%9A%E6%89%A9%E5%B1%95%E5%8E%9F%E7%94%9F%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%8E%9F%E5%9E%8B"><span class="nav-text">错误实践：扩展原生对象的原型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%80%BB%E7%BB%93%EF%BC%9A4-%E4%B8%AA%E7%94%A8%E4%BA%8E%E6%8B%93%E5%B1%95%E5%8E%9F%E5%9E%8B%E9%93%BE%E7%9A%84%E6%96%B9%E6%B3%95"><span class="nav-text">总结：4 个用于拓展原型链的方法</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#New-initialization"><span class="nav-text">New-initialization</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Object-create"><span class="nav-text">Object.create</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Object-setPrototypeOf"><span class="nav-text">Object.setPrototypeOf</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#proto"><span class="nav-text">__proto__</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#prototype-%E5%92%8C-Object-getPrototypeOf"><span class="nav-text">prototype 和 Object.getPrototypeOf</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%93%E8%AE%BA"><span class="nav-text">结论</span></a></li></ol></div></div></aside><div class="image-viewer-container"><img src=""></div><div class="search-pop-overlay"><div class="popup search-popup"><div class="search-header"><span class="search-input-field-pre"><i class="fas fa-keyboard"></i></span><div class="search-input-container"><input autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="搜索..." spellcheck="false" type="search" class="search-input"></div><span class="popup-btn-close"><i class="fas fa-times"></i></span></div><div id="search-result"><div id="no-result"><i class="fas fa-spinner fa-pulse fa-5x fa-fw"></i></div></div></div></div></main><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/js/header-shrink.js"></script><script src="/js/back2top.js"></script><script src="/js/dark-light-toggle.js"></script><script src="/js/local-search.js"></script><script src="/js/code-copy.js"></script><script src="/js/lazyload.js"></script><div class="post-scripts pjax"><script src="/js/left-side-toggle.js"></script><script src="/js/libs/anime.min.js"></script><script src="/js/toc.js"></script></div><script src="/js/libs/pjax.min.js"></script><script>window.addEventListener("DOMContentLoaded",()=>{window.pjax=new Pjax({selectors:["head title",".page-container",".pjax"],history:!0,debug:!1,cacheBust:!1,timeout:0,analytics:!1,currentUrlFullReload:!1,scrollRestoration:!1}),document.addEventListener("pjax:send",()=>{KEEP.utils.pjaxProgressBarStart()}),document.addEventListener("pjax:complete",()=>{KEEP.utils.pjaxProgressBarEnd(),window.pjax.executeScripts(document.querySelectorAll("script[data-pjax], .pjax script")),KEEP.refresh()})})</script></body></html>